package com.ibm.pess.rest;

import java.io.IOException;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.log4j.Logger;
import com.ibm.json.java.JSONArray;
import com.ibm.json.java.JSONObject;

public class RestClient {

	private static Logger log = Logger.getLogger("log");

	public static JSONArray getJSONArray(String url, String user,
			String password) throws Exception {
		log.info("  url=" + url);
		log.info("  user=" + user);
		log.info("  password=" + password);
		prepareSecurity(user, password);
		HttpURLConnection huc = (HttpURLConnection) new URL(url)
				.openConnection();
		prepareHeader(huc);
		int respCode = huc.getResponseCode();
		log.info("GET " + url + " with response " + respCode);
		JSONArray result = JSONArray.parse(huc.getInputStream());
		log.info(result);
		return result;
	}

	public static void delete(String url, String user, String password) {
		try {
			prepareSecurity(user, password);
			HttpURLConnection huc = (HttpURLConnection) new URL(url)
					.openConnection();
			prepareHeader(huc);

			huc.addRequestProperty("Content-Type", "application/json");
			huc.setRequestMethod("DELETE");
			int respCode = huc.getResponseCode();
			System.out.println("delete " + url + " with response " + respCode);
			huc.disconnect();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void postJSONObject(String url, String user, String password,
			JSONObject obj) throws Exception {
		prepareSecurity(user, password);
		HttpURLConnection huc = (HttpURLConnection) new URL(url)
				.openConnection();
		prepareHeader(huc);

		huc.addRequestProperty("Content-Type", "application/json");
		huc.setRequestMethod("POST");

		obj.serialize(System.out, true);
		huc.setDoOutput(true);
		huc.getOutputStream().write(obj.serialize().getBytes());
		huc.getOutputStream().flush();

		int respCode = huc.getResponseCode();
		System.out.println("PUT " + url + " with response " + respCode);
		huc.disconnect();
	}

	public static JSONObject putJSONObject(String url, String user,
			String password, JSONObject request) throws Exception {
		prepareSecurity(user, password);
		JSONObject response = new JSONObject();
		HttpURLConnection huc = (HttpURLConnection) new URL(url)
				.openConnection();
		prepareHeader(huc);

		huc.addRequestProperty("Content-Type", "application/json");
		huc.setRequestMethod("PUT");

		request.serialize(System.out, true);
		huc.setDoOutput(true);
		huc.getOutputStream().write(request.serialize().getBytes());
		huc.getOutputStream().flush();

		int respCode = huc.getResponseCode();
		System.out.println("PUT " + url + " with response " + respCode);

		try {
			response = JSONObject.parse(huc.getInputStream());
		} catch (IOException e) {
			response.put("message", "return is empty or not a JSONObject.");
		}
		return response;
	}

	/**
	 * <p>
	 * Title: get
	 * </p>
	 * <p>
	 * Description: provide get method, simply pass a suffix , such as
	 * "readtags" which is attached in Router
	 * </p>
	 * 
	 * @param suffix
	 * @return
	 * @throws Exception
	 */
	public static JSONObject getJSONObject(String url, String user,
			String password) throws Exception {
		prepareSecurity(user, password);
		HttpURLConnection huc = (HttpURLConnection) new URL(url)
				.openConnection();
		prepareHeader(huc);

		int respCode = huc.getResponseCode();
		log.info("GET " + url + " with response " + respCode);

		JSONObject result = JSONObject.parse(huc.getInputStream());
		log.info(result);
		return result;
	}

	private static void prepareHeader(HttpURLConnection huc) throws Exception {
		huc.addRequestProperty("X-IBM-Workload-Deployer-API-Version", "3.1");
		huc.addRequestProperty("Accept", "application/json");
	}

	private static void prepareSecurity(final String user, final String password)
			throws Exception {
		// Set authenticator
		Authenticator.setDefault(new Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(user, password.toCharArray());
			}
		});

		// Accept all the SSL cert
		SSLContext context = getSSLContext();
		HostnameVerifier hv = new HostnameVerifier() {
			public boolean verify(String hostname, SSLSession session) {
				// Accept all the host
				return true;
			}
		};
		HttpsURLConnection.setDefaultSSLSocketFactory(context
				.getSocketFactory());
		HttpsURLConnection.setDefaultHostnameVerifier(hv);
	}

	private static class AcceptAllTrustManager implements X509TrustManager {
		public void checkClientTrusted(X509Certificate[] arg0, String arg1)
				throws CertificateException {
			// Does nothing, accepts all
		}

		public void checkServerTrusted(X509Certificate[] arg0, String arg1)
				throws CertificateException {
			// Does nothing, accepts all
		}

		public X509Certificate[] getAcceptedIssuers() {
			return null;
		}
	}

	private static SSLContext getSSLContext() throws NoSuchAlgorithmException,
			KeyManagementException {
		// Get the SSL context
		SSLContext context = null;
		context = SSLContext.getInstance("SSL");
		TrustManager[] tms = new TrustManager[1];
		tms[0] = new AcceptAllTrustManager();

		// Use default random number generator (param3)
		context.init(null, tms, null);
		return context;
	}

	// public static void main(String[] args) throws Exception {
	// String protocal = "http";
	// String host = "localhost";
	// String port = "8080";
	// String context = "se";
	// String patternRoot = "rest";
	// String user = "scott";
	// String password = "";
	// ReaderClient reader = new ReaderClient(protocal, host, port, context,
	// patternRoot, user, password);
	// JSONObject tags = reader.readTags();
	//
	// System.out.println("========tags======");
	// System.out.println(tags.toString());
	// }
}
